/** @file widget.h
 * @brief base class of FGUI
 * @author    - Adela 
 *            - Robert Zhang <armner@gmail.com>
 *            - Heynie Yao<aheynie@gamil.com>
 * @date 2013-05
 * @version 1.0.0
 * @note
 */

#ifndef _WIDGET_H_
#define _WIDGET_H_

#include "frgui.h"    ///< fgui structure
#include "message.h"    ///< iMsg definations
#include "msg_queue.h"    ///< Message Que handling
#include "gdi.h"    ///< point draw
#include "clip_rect.h"    ///< rectangle
#include "dc.h"    ///< Drawing Device Contect

extern "C" void __cxa_pure_virtual(void);

/** @name  Signal matching
 * @def SIGNAL_MATCH(signal, psignal)
 * @brief test if the MSG_SIGNAL matches to a signal
 */
#define SIGNAL_MATCH(signal, psignal)  (signal==(WPARAM)psignal)

/** @class Wight widget.h "core/widget.h"
 * @brief base class of FGUI
 */
class Widget
{
public:
    
    Widget(HWND parent=0);/**< @brief constructor */    
    virtual ~Widget();/**< @brief destructor */

    char *name;    ///< name
    HWND parent;    ///< parent index
    HWND childList;     ///< first child
    HWND activeChild;   ///< currunt active child
    HWND prev;    ///< elder brother
    HWND next;     ///< younger brother

    bool activable;     ///< could gain key focus
    
    /** @brief tbe the active child of paren 
     * @return bool
     * @note The parent window is activated
     */
    bool isActive(){return parent? parent->activeChild ==this: false;} 
 
    int lifeState;      ///< 0: OK; -1: CANCEL; 1:LIVE

    //location
    Rect rect;    ///< widget location and size
    DC *pDC;    ///< drawing context
    
    
    void setupDC();/**< @brief setup drawing context */    
    void releaseDC();/**< @brief release drawing context */    
    void resetDC();/**< @brief reset drawing context */

   
    void setPosition(short x, short y); /**< @brief moving to a position to +x,+y */     
    void setSize(short w, short h);/**< @brief resize rect to w,h   */    
    /** @brief get top margin  
     * @return short rect.y0
     */    
    short up() {return rect.y0;}
    /** @brief get bottom margin  
     * @return short rect.y1
     */ 
    short bottom() {return rect.y1;}
    /** @brief get left margin  
     * @return short rect.x0
     */  
    short left() {return rect.x0;}
    /** @brief get right margin   
     * @return short rect.x1
     */    
    short right() {return rect.x1;} 
    /** @brief get width    
     * @return short w
     */    
    short sizew(){short w; w=rect.x1-rect.x0; if(w>0) return w; else return 0;}
    /** @brief get hight    
     * @return short h
     */     
    short sizeh(){short h; h=rect.y1-rect.y0; if(h>0) return h; else return 0;}
    
    
    //widget event handler    
    virtual int eventHandler(HWND hWnd, int iMsg, WPARAM wParam, LPARAM lParam);/**< @brief different handler for varies widgets  */     
    virtual int defaultHandler(HWND hWnd, int iMsg, WPARAM wParam, LPARAM lParam); /**< @brief default handler of widget  */
        
    void sendChildMessage(HWND hWnd, int iMsg, WPARAM wParam, LPARAM lParam);/**< @brief send message to children  */
    
    void setParent(HWND parent);/**< @brief add to parent's child list  */    
    void unlinkParent();/**< @brief remove from parent  */    
    void activeNextChild();/**< @brief make the younger brother active  */    
    void activePrevChild();/**< @brief make the elder brother active  */    
    void activeFirstChild();/**< @brief make the first child active  */
    void operator delete(void *);/**< @brief operator 'delete' definitions  */    
    void *operator new(unsigned int len);/**< @brief operator 'new' definitions  */    
    void close();/**< @brief window close  */    
    void create();/**< @brief window create  */    
    virtual void draw(Rect *r)=0;/**< @brief window draw  */
    
    HWND getFirstItem(HWND *list){return *list;}/**< @brief get first window handle  */    
    void addChild(HWND child);/**< @brief add child window handle  */    
    void removeChild(HWND child);/**< @brief remove child window handle  */    
    
private:
    bool isListVacant(HWND *list){return *list;}/**< @brief is window list null   */    
    void listRemove(HWND *list, HWND item);/**< @brief list remove  */    
    void listInsertLast(HWND *list, HWND item);/**< @brief intsert  */    
    void activateWidget(HWND child); /**< @brief active designated child  */
    void deActivateWidget(HWND child);/**< @brief deactive designated child  */    
    virtual void leaveFocus(){}/**< @brief leave focus  */
    virtual void enterFocus(){}/**< @brief enter focus  */
    
};

#endif


